package com.example.usercenter.service.impl;

import cn.hutool.core.lang.Pair;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.usercenter.common.ErrorCode;
import com.example.usercenter.exception.ServiceException;
import com.example.usercenter.mapper.UserMapper;
import com.example.usercenter.model.domain.User;
import com.example.usercenter.service.UserService;
import com.example.usercenter.utils.AlgorithmUtils;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.example.usercenter.constants.UserConstant.CUR_USER;

/**
* @author 57017
* @description 针对表【t_user(用户表)】的数据库操作Service实现
* @createDate 2024-01-17 12:39:34
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService {

    private static final String SALT = "RICE"; // 加密盐值

    @Override
    public long userRegister(String account, String pwd, String rePwd) {
        // 1. 非空校验
        if (StringUtils.isAnyBlank(account, pwd, rePwd)) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 位数检验
        if (account.length() < 4) {
            throw new ServiceException(400, "账号长度过短！");
        }
        if (pwd.length() < 8) {
            throw new ServiceException(400, "密码长度过短！");
        }
        // 3. 密码一致性校验
        if (!pwd.equals(rePwd)) {
            throw new ServiceException(400, "密码与确认密码不一致！");
        }
        // 4. 特殊字符校验
        Matcher matcher = Pattern.compile("[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]|\n|\r|\t").matcher(account);
        if (matcher.find()) {
            // 说明有特殊字符
            throw new ServiceException(400, "账号包含特殊字符！");
        }
        // 5. 查询数据库
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", account);
        long count = this.count(queryWrapper);
        if (count >= 1) {
            // 说明有账号一致的
            throw new ServiceException(400, "该账号已经存在！");
        }
        // 6. 密码加密
        String enctypePwd = DigestUtils.md5DigestAsHex((SALT + pwd).getBytes());
        // 7. 新增用户
        User newUser = new User();
        newUser.setUserAccount(account);
        newUser.setUserPassword(enctypePwd);
        this.save(newUser);
        return newUser.getId();
    }

    @Override
    public User userLogin(String account, String pwd, HttpServletRequest request) {
        // 1. 非空校验
        if (StringUtils.isAnyBlank(account, pwd)) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 位数校验
        if (account.length() < 4) {
            throw new ServiceException(400, "账号长度过短！");
        }
        if (pwd.length() < 8) {
            throw new ServiceException(400, "密码长度过短！");
        }
        // 3. 特殊字符校验
        Matcher matcher = Pattern.compile("[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]").matcher(account);
        if (matcher.find()) {
            throw new ServiceException(400, "账号包含特殊字符！");
        }
        // 4. 加密密码
        String enctypePwd = DigestUtils.md5DigestAsHex((SALT + pwd).getBytes());
        // 5. 查询数据库
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", account);
        queryWrapper.eq("user_password", enctypePwd);
        User dbUser = this.getOne(queryWrapper);
        if (dbUser == null) {
            throw new ServiceException(400, "该用户不存在！");
        }
        // 6. 存入session
        request.getSession().setAttribute(CUR_USER, dbUser);
        // 7. 脱敏返回给前端
        return getSafetyUser(dbUser);
    }

    @Override
    public User getSafetyUser(User dbUser) {
        User retUser = new User();
        retUser.setId(dbUser.getId());
        retUser.setUserAccount(dbUser.getUserAccount());
        retUser.setUserPassword("");
        retUser.setEmail(dbUser.getEmail());
        retUser.setPhone(dbUser.getPhone());
        retUser.setGender(dbUser.getGender());
        retUser.setAvatarUrl(dbUser.getAvatarUrl());
        retUser.setUsername(dbUser.getUsername());
        retUser.setCreateTime(dbUser.getCreateTime());
        retUser.setUserStatus(dbUser.getUserStatus());
        retUser.setUserRole(dbUser.getUserRole());
        retUser.setUserTags(dbUser.getUserTags());
        retUser.setUserProfile(dbUser.getUserProfile());
        return retUser;
    }

    @Override
    public List<User> matchUserList(int num, User loginUser) {
        Gson gson = new Gson();
        // 1. 获取到登录用户标签
        String[] loginUserTagList = gson.fromJson(loginUser.getUserTags(), new TypeToken<String[]>(){}.getType());
        // 2. 查询全量用户（优化查询条件）
        List<User> userList = this.list(new QueryWrapper<User>()
                .select("id", "user_tags"));
        // 3. 借助优先级队列TopK思想
        PriorityQueue<Pair<User, Integer>> queue = new PriorityQueue<>((pair1, pair2) -> {
            return pair2.getValue() - pair1.getValue();
        });
        for (User dbUser : userList) {
            if (loginUser.getId().equals(dbUser.getId())) {
                // 过滤自身
                continue;
            }
            // 获取匹配用户标签列表
            String[] tagList = gson.fromJson(dbUser.getUserTags(), new TypeToken<String[]>(){}.getType());
            // 获取编辑距离
            int dist = AlgorithmUtils.minDistance(tagList, loginUserTagList);
            if (queue.size() < num) {
                // 直接加入
                queue.offer(new Pair<>(dbUser, dist));
            } else {
                // 取出队头编辑距离
                int topDist = queue.peek().getValue();
                if (dist < topDist) {
                    queue.poll();
                    queue.offer(new Pair<>(dbUser, dist));
                }
            }
        }
        // 4. 取出TopK用户列表返回
        List<User> matchUserList = new ArrayList<>();
        while (!queue.isEmpty()) {
            long id = queue.poll().getKey().getId();
            matchUserList.add(0, this.getById(id)); // 需要查询该id的用户
        }
        // 5. 脱敏返回
        matchUserList = matchUserList
                .stream()
                .map(this::getSafetyUser)
                .collect(Collectors.toList());
        return matchUserList;
    }

    @Override
    public List<User> getUsesByUsername(String username) {
        // 1. 定义查询条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("username", username);
        // 2. 查询
        return this.list(queryWrapper);
    }

    @Override
    public boolean deleteUserById(Integer userId) {
        // 1. 删除id不得小于等于0
        if (userId <= 0) {
            new ServiceException(400, "删除失败！");
        }
        return this.removeById(userId);
    }

//    // 实现方式一
//    @Override
//    public List<User> matchUsersByTagName(List<String> tagList) {
//        // 1. 集合判空
//        if (CollectionUtils.isEmpty(tagList)) {
//            throw new ServiceException(ErrorCode.PARAMS_NULL);
//        }
//        // 2. 定义查询条件（方式一）
//        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//        for (String tag : tagList) {
//            queryWrapper = queryWrapper.like("user_tags", tag);
//        }
//        // 3. 进行查询
//        List<User> userList = this.list(queryWrapper);
//        return userList;
//    }

    // 实现方式二
    @Override
    public List<User> matchUsersByTagName(List<String> tagList) {
        // 1. 集合判空
        if (CollectionUtils.isEmpty(tagList)) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 定义查询条件（方式二）
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 3. 进行查询
        List<User> userList = this.list(queryWrapper);
        // 4. 集合过滤
        Gson gson = new Gson();
        return userList.stream().filter((ele) -> {
            // 4.1 解析JSON字符串
            Set<String> fromJsonSet = gson.fromJson(ele.getUserTags(), new TypeToken<Set<String>>() {
            }.getType());
            Set<String> set = Optional.ofNullable(fromJsonSet).orElse(new HashSet<>());
            for (String tag : tagList) {
                if (!set.contains(tag)) {
                    return false;
                }
            }
            return true;
        }).map(this::getSafetyUser)
                .collect(Collectors.toList());
    }

    @Override
    public boolean editUser(User user, HttpSession session) {
        // 1. 字段验证
        if (user == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 验证编辑用户id
        Long id = user.getId();
        if (id == null || id <= 0) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        // 3. 验证用户权限
        User loginUser = getLoginUser(session);
        if (!isAdmin(session) && !loginUser.getId().equals(id)) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        // 4. 进行修改
        return this.updateById(user);
    }

    @Override
    public boolean isAdmin(HttpSession session) {
        User loginUser = getLoginUser(session);
        return loginUser.getUserRole() == 1;
    }

    @Override
    public User getLoginUser(HttpSession session) {
        // 1. 从session中获取
        Object curUserObj = session.getAttribute(CUR_USER);
        User curUser = (User) curUserObj;
        // 2. 判断curUser是否为空
        if (curUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        return curUser;
    }
}




